﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Devonline.AspNetCore;

/// <summary>
/// 附件及文件操作类服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TAttachment">附件</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public interface IAttachmentService<TDbContext, TAttachment, TKey>
    where TDbContext : DbContext
    where TAttachment : class, IAttachment<TKey>
    where TKey : IConvertible
{
    /// <summary>
    /// 获取并返回文件名指向的物理文件
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <returns></returns>
    IActionResult GetFile(string fileName);
    /// <summary>
    /// 文件下载, 提供类似于文件夹目录结构的访问方式进行下载
    /// 形如 2020-01-01/xxx.jpg
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="filePath">文件路径</param>
    /// <returns></returns>
    Task<TAttachment?> GetAttachmentAsync(string? fileName, string? filePath = null);
    /// <summary>
    /// 获取附件对应的文件, 适用于文件下载
    /// 形如 2020-01-01/xxx.jpg
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="filePath">文件路径</param>
    /// <returns></returns>
    Task<IActionResult> GetAttachmentFileAsync(string? fileName, string? filePath = null);
    /// <summary>
    /// 获取文件, 按业务类型和业务主键获取
    /// </summary>
    /// <param name="businessType">业务类型</param>
    /// <param name="businessKey">业务主键</param>
    /// <returns></returns>
    Task<IEnumerable<TAttachment>?> GetAttachmentsAsync(string? businessType = null, TKey? businessKey = default);

    /// <summary>
    /// 单个文件上传
    /// </summary>
    /// <param name="file"></param>
    /// <returns></returns>
    Task<UploadResult<TAttachment, TKey>> UploadAsync(IFormFile? file = null);
    /// <summary>
    /// 批量文件上传
    /// </summary>
    /// <param name="files"></param>
    /// <returns></returns>
    Task<IEnumerable<UploadResult<TAttachment, TKey>>> UploadAsync(IEnumerable<IFormFile>? files = null);

    /// <summary>
    /// 删除附件物理文件, 请在附件相关操作的事物提交之后执行此方法
    /// </summary>
    /// <param name="files">待删除的文件</param>
    void Delete(IEnumerable<string> files);

    /// <summary>
    /// 新增附件
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task AddAttachmentsAsync<TEntitySet>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 修改附件, 保留旧附件, 新增新附件, 返回待删除文件列表
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task<IEnumerable<string>> UpdateAttachmentsAsync<TEntitySet>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 自动删除附件, 返回待删除文件列表, 适用于实体对象模型从数据库删除时查找原始附件并自动删除
    /// </summary>
    /// <param name="businessKey">业务主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task<IEnumerable<string>?> DeleteAttachmentsAsync(TKey businessKey, string? businessType = default, bool isLogical = false);
    /// <summary>
    /// 按文件列表删除附件
    /// </summary>
    /// <param name="fileNames">待删除的文件名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<IEnumerable<string>?> DeleteAttachmentsAsync(IEnumerable<string> fileNames, bool isLogical = false);
}

/// <summary>
/// 附件及文件操作类服务
/// 字符串作为主键的默认实现
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
public interface IAttachmentService<TDbContext> : IAttachmentService<TDbContext, Attachment, string> where TDbContext : DbContext { }